Funwave-TVD

Funwave-TVD is a code to simulate the shallow water and Boussinesq equations written by Dr. Fengyan Shi. It is capable of running a variety of complex ocean simulations. For more information, see Dr. Fengyan Shi's website: https://fengyanshi.github.io/shi_website/_build/html/funwave.html

We will use it as our example scientific code for this tutorial because it is reasonably complex, real scientific code but can be compiled and run quickly.


In [1]:
!mkdir -p ~/agave

%cd ~/agave

!pip3 install --upgrade setvar

import re
import os
import sys
from setvar import *
from time import sleep

# This cell enables inline plotting in the notebook
%matplotlib inline

import matplotlib
import numpy as np
import matplotlib.pyplot as plt


/home/jovyan/agave
Requirement already up-to-date: setvar in /opt/conda/lib/python3.6/site-packages

The parameter file for Funwave-TVD is called "input.txt". Here we create it using writefile. You don't need to understand the details of how this file for this tutorial.


In [2]:
writefile("input.txt","""
!INPUT FILE FOR FUNWAVE_TVD
  ! NOTE: all input parameter are capital sensitive
  ! --------------------TITLE-------------------------------------
  ! title only for log file
TITLE = VESSEL
  ! -------------------HOT START---------------------------------
HOT_START = F
FileNumber_HOTSTART = 1
  ! -------------------PARALLEL INFO-----------------------------
  ! 
  !    PX,PY - processor numbers in X and Y
  !    NOTE: make sure consistency with mpirun -np n (px*py)
  !    
PX = 2
PY = 1
  ! --------------------DEPTH-------------------------------------
  ! Depth types, DEPTH_TYPE=DATA: from depth file
  !              DEPTH_TYPE=FLAT: idealized flat, need depth_flat
  !              DEPTH_TYPE=SLOPE: idealized slope, 
  !                                 need slope,SLP starting point, Xslp
  !                                 and depth_flat
DEPTH_TYPE = FLAT
DEPTH_FLAT = 10.0
  ! -------------------PRINT---------------------------------
  ! PRINT*,
  ! result folder
RESULT_FOLDER = output/

  ! ------------------DIMENSION-----------------------------
  ! global grid dimension
Mglob = 500
Nglob = 100

  ! ----------------- TIME----------------------------------
  ! time: total computational time/ plot time / screen interval 
  ! all in seconds
TOTAL_TIME = 3.0
PLOT_INTV = 1.0
PLOT_INTV_STATION = 50000.0
SCREEN_INTV = 1.0
HOTSTART_INTV = 360000000000.0

WAVEMAKER = INI_GAU
AMP = 3.0
Xc = 250.0
Yc = 50.0
WID = 20.0

  ! -----------------GRID----------------------------------
  ! if use spherical grid, in decimal degrees
  ! cartesian grid sizes
DX = 1.0
DY = 1.0
  ! ----------------SHIP WAKES ----------------------------
VESSEL_FOLDER = ./
NumVessel = 2
  ! -----------------OUTPUT-----------------------------
ETA = T
U = T
V = T
""")


Writing file `input.txt'

Here is a simple bash script to run the code....


In [3]:
writefile("run.sh","""
#!/bin/bash
export LD_LIBRARY_PATH=/usr/local/lib
mkdir -p rundir
cd ./rundir
cp ../input.txt .
mpirun -np 2 ~/FUNWAVE-TVD/src/funwave_vessel
""")


Writing file `run.sh'

FOLLOWING ALONG AT HOME

If you are following along at home using the docker-compose stack, you will need to run the following cell to get the hsotname and port of your tcp tunnel so Agave can contact your system without a public IP address.


In [4]:
if os.environ.get('USE_TUNNEL') == 'True': 
    # fetch the hostname and port of the reverse tunnel running in the sandbox 
    # so Agave can connect to our local sandbox
    !echo $(ssh -q -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null sandbox 'curl -s  http://localhost:4040/api/tunnels | jq -r '.tunnels[0].public_url'') > ngrok_url.txt  
    !cat ngrok_url.txt | sed 's|^tcp://||'
    !cat ngrok_url.txt | sed 's|^tcp://||' | sed -r 's#(.*):(.*)#\1#' > ngrok_host.txt
    !cat ngrok_url.txt | sed 's|^tcp://||' | sed -r 's#(.*):(.*)#\2#' > ngrok_port.txt

    # set the environment variables otherwise set when running in a training cluster
    os.environ['VM_PORT'] = readfile('ngrok_port.txt').strip()
    os.environ['VM_MACHINE'] = readfile('ngrok_host.txt').strip()
    os.environ['AGAVE_SYSTEM_HOST'] = readfile('ngrok_host.txt').strip()
    os.environ['AGAVE_SYSTEM_PORT'] = readfile('ngrok_port.txt').strip()
    !echo "VM_PORT=$VM_PORT"
    !echo "VM_MACHINE=$VM_MACHINE"
    setvar("VM_IPADDRESS=$(getent hosts ${VM_MACHINE}|cut -d' ' -f1)")


0.tcp.ngrok.io:10322
Reading file `ngrok_port.txt'
Reading file `ngrok_host.txt'
Reading file `ngrok_host.txt'
Reading file `ngrok_port.txt'
VM_PORT=10322
VM_MACHINE=0.tcp.ngrok.io
VM_IPADDRESS=52.15.194.28

Here's how the average developer might run the code when doing their research.


In [5]:
!scp -o "StrictHostKeyChecking=no" -P $VM_PORT input.txt run.sh $VM_IPADDRESS:.
!ssh -p $VM_PORT $VM_IPADDRESS bash run.sh


Warning: Permanently added '[52.15.194.28]:10322' (ECDSA) to the list of known hosts.
input.txt                                     100% 1753     1.7KB/s   00:00    
run.sh                                        100%  141     0.1KB/s   00:00    
Warning: Permanently added '[52.15.194.28]:10322' (ECDSA) to the list of known hosts.
 BATHY_CORRECTION DOES NOT EXIST. USE DEFAULT VALUE
 INI_UVZ DOES NOT EXIST. USE DEFAULT VALUE
 WaterLevel DOES NOT EXIST. USE DEFAULT VALUE
 ETA_LIMITER DOES NOT EXIST. USE DEFAULT VALUE
 EqualEnergy DOES NOT EXIST. USE DEFAULT VALUE
 PERIODIC DOES NOT EXIST. USE DEFAULT VALUE
 DIFFUSION_SPONGE DOES NOT EXIST. USE DEFAULT VALUE
 DIRECT_SPONGE DOES NOT EXIST. USE DEFAULT VALUE
 FRICTION_SPONGE DOES NOT EXIST. USE DEFAULT VALUE
 OBSTACLE_FILE DOES NOT EXIST. USE DEFAULT VALUE
 BREAKWATER_FILE DOES NOT EXIST. USE DEFAULT VALUE
 DISPERSION DOES NOT EXIST. USE DEFAULT VALUE
         DISPERSION Default:  DISPERSION
 Gamma1 DOES NOT EXIST. USE DEFAULT VALUE
        Gamma1 Default:  1.0: DISPERSION
 Gamma2 DOES NOT EXIST. USE DEFAULT VALUE
              Gamma2 Default:  1.0: Full nonlinear
 Beta_ref DOES NOT EXIST. USE DEFAULT VALUE
               Beta_ref Default:  -0.531
 Gamma3 DOES NOT EXIST. USE DEFAULT VALUE
                      Gamma3 Default:  1.0: NOT fully linear
 VISCOSITY_BREAKING DOES NOT EXIST. USE DEFAULT VALUE
                   VISCOSITY_BREAKING Default:  SWE Breaking
 SWE_ETA_DEP DOES NOT EXIST. USE DEFAULT VALUE
               SWE_ETA_DEP Default:  0.8
 Friction_Matrix DOES NOT EXIST. USE DEFAULT VALUE
             Friction_Matrix Default:  constant Cd
 Cd DOES NOT EXIST. USE DEFAULT VALUE
                  Cd_fixed Default:  0.0
 Time_Scheme DOES NOT EXIST. USE DEFAULT VALUE
       Time_Scheme Default:  Runge_Kutta
 CONSTRUCTION DOES NOT EXIST. USE DEFAULT VALUE
 HIGH_ORDER DOES NOT EXIST. USE DEFAULT VALUE
  HIGH_ORDER                     NOT DEFINED, USE FOURTH-ORDER
 CFL DOES NOT EXIST. USE DEFAULT VALUE
                       CFL Default:  0.5
 DT_fixed DOES NOT EXIST. USE DEFAULT VALUE
 FroudeCap DOES NOT EXIST. USE DEFAULT VALUE
                 FroudeCap Default:  3.0
 MinDepth DOES NOT EXIST. USE DEFAULT VALUE
                MinDepth Default:  0.1 m
 MinDepthFrc DOES NOT EXIST. USE DEFAULT VALUE
             MinDepthFrc Default:  0.1 m
 SHOW_BREAKING DOES NOT EXIST. USE DEFAULT VALUE
            SHOW_BREAKING Default:  TRUE
 Cbrk1 DOES NOT EXIST. USE DEFAULT VALUE
                    Cbrk1 Default:  0.65
 Cbrk2 DOES NOT EXIST. USE DEFAULT VALUE
                    Cbrk2 Default:  0.35
 WAVEMAKER_Cbrk DOES NOT EXIST. USE DEFAULT VALUE
            WAVEMAKER_Cbrk Default:  1.0
 WAVEMAKER_VIS DOES NOT EXIST. USE DEFAULT VALUE
           WAVEMAKER_VIS Default:  FALSE
 T_INTV_mean DOES NOT EXIST. USE DEFAULT VALUE
             T_INTV_mean Default:  LARGE
 STEADY_TIME DOES NOT EXIST. USE DEFAULT VALUE
             STEADY_TIME Default:  LARGE
 C_smg DOES NOT EXIST. USE DEFAULT VALUE
                     C_smg Default:  0.0
 nu_bkg DOES NOT EXIST. USE DEFAULT VALUE
                    nu_bkg Default:  0.0
 FIELD_IO_TYPE DOES NOT EXIST. USE DEFAULT VALUE
 NumberStations DOES NOT EXIST. USE DEFAULT VALUE
 OUTPUT_RES DOES NOT EXIST. USE DEFAULT VALUE
         OUTPUT_RES NOT FOUND, OUTPUT_RES=1: full resolution
 DEPTH_OUT DOES NOT EXIST. USE DEFAULT VALUE
 Hmax DOES NOT EXIST. USE DEFAULT VALUE
 Hmin DOES NOT EXIST. USE DEFAULT VALUE
 Umax DOES NOT EXIST. USE DEFAULT VALUE
 MFmax DOES NOT EXIST. USE DEFAULT VALUE
 VORmax DOES NOT EXIST. USE DEFAULT VALUE
 MASK DOES NOT EXIST. USE DEFAULT VALUE
 MASK9 DOES NOT EXIST. USE DEFAULT VALUE
 Umean DOES NOT EXIST. USE DEFAULT VALUE
 Vmean DOES NOT EXIST. USE DEFAULT VALUE
 ETAmean DOES NOT EXIST. USE DEFAULT VALUE
 WaveHeight DOES NOT EXIST. USE DEFAULT VALUE
 SXL DOES NOT EXIST. USE DEFAULT VALUE
 SXR DOES NOT EXIST. USE DEFAULT VALUE
 SYL DOES NOT EXIST. USE DEFAULT VALUE
 SYR DOES NOT EXIST. USE DEFAULT VALUE
 SourceX DOES NOT EXIST. USE DEFAULT VALUE
 SourceY DOES NOT EXIST. USE DEFAULT VALUE
 P DOES NOT EXIST. USE DEFAULT VALUE
 Q DOES NOT EXIST. USE DEFAULT VALUE
 Fx DOES NOT EXIST. USE DEFAULT VALUE
 Fy DOES NOT EXIST. USE DEFAULT VALUE
 Gx DOES NOT EXIST. USE DEFAULT VALUE
 Gy DOES NOT EXIST. USE DEFAULT VALUE
 AGE DOES NOT EXIST. USE DEFAULT VALUE
 OUT_NU DOES NOT EXIST. USE DEFAULT VALUE
 TMP DOES NOT EXIST. USE DEFAULT VALUE
      EtaBlowVal Default:  100xmax_depth
 ----------------- STATISTICS ----------------
  TIME        DT
  0.4428E-01  0.4428E-01
  MassVolume  Energy      MaxEta      MinEta      Max U       Max V 
  0.1937E+04  0.1247E+08  0.2996E+01 -0.4596E-06  0.4050E-01  0.4050E-01
  MaxTotalU   PhaseS      Froude 
  0.4050E-01  0.1066E+02  0.3800E-02
   PRINTING FILE NO.     1  TIME/TOTAL:        0.044 /       3.000
 ----------------- STATISTICS ----------------
  TIME        DT
  0.1017E+01  0.4414E-01
  MassVolume  Energy      MaxEta      MinEta      Max U       Max V 
  0.1927E+04  0.1246E+08  0.1900E+01 -0.1727E-05  0.7329E+00  0.7325E+00
  MaxTotalU   PhaseS      Froude 
  0.7338E+00  0.1050E+02  0.6987E-01
   PRINTING FILE NO.     2  TIME/TOTAL:        1.017 /       3.000
 ----------------- STATISTICS ----------------
  TIME        DT
  0.2037E+01  0.4473E-01
  MassVolume  Energy      MaxEta      MinEta      Max U       Max V 
  0.1906E+04  0.1246E+08  0.7393E+00 -0.2109E-05  0.9186E+00  0.9148E+00
  MaxTotalU   PhaseS      Froude 
  0.9215E+00  0.1024E+02  0.8998E-01
   PRINTING FILE NO.     3  TIME/TOTAL:        2.037 /       3.000
 ----------------- STATISTICS ----------------
  TIME        DT
  0.3032E+01  0.4566E-01
  MassVolume  Energy      MaxEta      MinEta      Max U       Max V 
  0.1890E+04  0.1246E+08  0.7188E+00 -0.9413E+00  0.7352E+00  0.6932E+00
  MaxTotalU   PhaseS      Froude 
  0.7378E+00  0.1019E+02  0.7239E-01
   PRINTING FILE NO.     4  TIME/TOTAL:        3.032 /       3.000
 Simulation takes   15.384583986000507      seconds
 Normal Termination!

Here's how they might retrieve the data.


In [6]:
!ssh -p $VM_PORT $VM_IPADDRESS tar -C rundir -czf output.tgz output
!rm -fr output.tgz output
!scp -q -r -P $VM_PORT $VM_IPADDRESS:output.tgz .
!tar xzf output.tgz




In [7]:
!ls output


eta_00001  eta_00003  eta_00005  u_00002  u_00004  v_00001  v_00003  v_00005
eta_00002  eta_00004  u_00001	 u_00003  u_00005  v_00002  v_00004

Now let's use Python to graph the output


In [8]:
data = np.genfromtxt("output/v_00003")
fig = plt.figure(figsize=(12,12))
pltres = plt.imshow(data[::-1,:])
plt.show()



In [ ]: